﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System.Windows;
using Razre.Base;

namespace Razre
{
    /// <summary>
    /// Class to provide Navigation Management mechanisms
    /// </summary>
    public static class NavigationManager
    {
        #region ctors

        /// <summary>
        /// Default statis constructor initializes the lock object
        /// </summary>
        static NavigationManager()
        {
            _Lock = new object();
        }

        #endregion


        #region Static fields

        /// <summary>
        /// Static store for the main region to be navigated too
        /// </summary>
        private static ContentControl _MainRegion = null;

        /// <summary>
        /// The Currently loaded View in the main region
        /// </summary>
        private static ContentControl _CurrentView = null;

        /// <summary>
        /// The previously navigated view in the main region
        /// </summary>
        private static ContentControl _PreviousView = null;

        /// <summary>
        /// The current storyboard created for a transition animation
        /// </summary>
        private static Storyboard _CurrentStoryboard = null;

        /// <summary>
        /// The grid used to provide an animation transition
        /// </summary>
        private static Grid _TransitionGrid = null;

        /// <summary>
        /// The lock object used to ensure synchronous static calls
        /// </summary>
        private static object _Lock { get; set; }

        /// <summary>
        /// Static event that notifies when the navigation manager is requesting an animation transition.
        /// This is provided by setting the Storyboard property of the arguments
        /// </summary>
        public static event EventHandler<RequestTransitionAnimationEventArgs> OnRequestTransitionAnimation;

        #endregion

        #region Public Methods

        /// <summary>
        /// Method to set the intended main region for navigation
        /// </summary>
        /// <param name="mainRegion">ContentControl to host the MainRegion</param>
        public static void SetMainRegion(ContentControl mainRegion)
        {
            lock (_Lock)
            {
                //Store the main region, create the transition grid and set the content
                _MainRegion = mainRegion;
                _TransitionGrid = new Grid();
                _MainRegion.Content = _TransitionGrid;
            }
        }

        /// <summary>
        /// Provides navigation of a ViewModel to the MainRegion
        /// </summary>
        /// <param name="viewModel">The ViewModel to navigate to</param>
        public static void Navigate(BaseViewModel viewModel)
        {
            //Navigate to the ViewModel's View
            Navigate(viewModel.View);
        }

        /// <summary>
        /// Provides navigation of a ContentControl to the MainRegion
        /// </summary>
        /// <param name="controlToNavigateTo">ContentControl to navigate to</param>
        public static void Navigate(ContentControl controlToNavigateTo)
        {
            try
            {
                lock (_Lock)
                {
                    //Ensure we have a MainRegion
                    if (_MainRegion != null)
                    {
                        //add view we are navigating too behind the currently loaded view, or as the first child
                        _TransitionGrid.Children.Add(controlToNavigateTo);

                        RequestTransitionAnimationEventArgs args = new RequestTransitionAnimationEventArgs();

                        //If an animation request handler has been set
                        if (OnRequestTransitionAnimation != null)
                        {
                            //store the current loaded and next views and invoke the event
                            args.CurrentView = _CurrentView;
                            args.NextView = controlToNavigateTo;

                            OnRequestTransitionAnimation(null, args);
                        }

                        //store the current view as the previous and the new view as the current
                        _PreviousView = _CurrentView;
                        _CurrentView = controlToNavigateTo;

                        //if a result was found and animates were defined
                        if (args.Result != null && args.Result.Children.Count > 0)
                        {
                            //store the storyboard and begin it
                            _CurrentStoryboard = args.Result;

                            _CurrentStoryboard.Completed += new EventHandler(CurrentStoryboard_Completed);
                            _CurrentStoryboard.Begin();
                        }
                        else
                        {
                            //if there is more than 1 child remove the previously loaded view
                            if (_TransitionGrid.Children.Count > 1)
                            {
                                _TransitionGrid.Children.RemoveAt(0);
                            }
                        }
                    }
                    else
                    {
                        throw new Exception("Main region not yet set");
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("An Exception occurred during Navigation, please see the inner exception for the details", ex);
            }
        }

        /// <summary>
        /// Method provides Back functionality by 1 View
        /// </summary>
        public static void Back()
        {
            try
            {
                lock (_Lock)
                {
                    //Make sure a MainRegion was set
                    if (_MainRegion != null)
                    {
                        //if nothing has been navigated to previously
                        if (_PreviousView == null || _CurrentView == null)
                        {
                            throw new Exception("There is no View to navigate Back to");
                        }

                        //Add the previously navigated view to the transition grid
                        _TransitionGrid.Children.Add(_PreviousView);

                        RequestTransitionAnimationEventArgs args = new RequestTransitionAnimationEventArgs();

                        //If an animation request handler has been set
                        if (OnRequestTransitionAnimation != null)
                        {
                            //store the current loaded and next views and invoke the event
                            args.CurrentView = _CurrentView;
                            args.NextView = _PreviousView;

                            OnRequestTransitionAnimation(null, args);
                        }

                        //store the previous view as the current view
                        _CurrentView = _PreviousView;

                        //if a result was found and animates were defined
                        if (args.Result != null && args.Result.Children.Count > 0)
                        {
                            //store the storyboard and begin it
                            _CurrentStoryboard = args.Result;

                            _CurrentStoryboard.Completed += new EventHandler(CurrentStoryboard_Completed);
                            _CurrentStoryboard.Begin();
                        }
                        else
                        {
                            //if there is more than 1 child remove the previously loaded view
                            if (_TransitionGrid.Children.Count > 1)
                            {
                                _TransitionGrid.Children.RemoveAt(0);
                            }
                        }
                    }
                    else
                    {
                        throw new Exception("Main region not yet set");
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("An Exception occurred during Back Navigation, please see the inner exception for the details", ex);
            }
        }

        /// <summary>
        /// Private handler for when a transition animation has been completed
        /// </summary>
        /// <param name="sender">Storyboard that was executed</param>
        /// <param name="e"></param>
        private static void CurrentStoryboard_Completed(object sender, EventArgs e)
        {
            //detach the completed handler
            _CurrentStoryboard.Completed -= CurrentStoryboard_Completed;

            //if there is more than 1 child remove the previously loaded view
            if (_TransitionGrid.Children.Count > 1)
            {
                _TransitionGrid.Children.RemoveAt(0);
            }
        }

        #endregion
    }

    /// <summary>
    /// Event Args to provide views for the transition and a result for the storyboard
    /// </summary>
    public class RequestTransitionAnimationEventArgs : EventArgs
    {
        /// <summary>
        /// The Currently loaded View
        /// </summary>
        public ContentControl CurrentView { get; internal set; }

        /// <summary>
        /// The View that is intended to navigate to
        /// </summary>
        public ContentControl NextView { get; internal set; }

        /// <summary>
        /// The storyboard created as a result
        /// </summary>
        public Storyboard Result { get; set; }
    }
}
